package top.lunarye.modules.staff.controller;


import ch.qos.logback.core.util.TimeUtil;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.GifCaptcha;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;
import top.lunarye.annotation.TokenToStaff;
import top.lunarye.modules.staff.entity.RoleEnum;
import top.lunarye.modules.staff.entity.Staff;
import top.lunarye.modules.staff.entity.dto.*;
import top.lunarye.modules.staff.service.IStaffService;
import top.lunarye.utils.DigesterUtil;
import top.lunarye.utils.RestResponse;
import top.lunarye.utils.SystemCode;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 人员表 前端控制器
 * </p>
 *
 * @author lunar
 * @since 2021-07-13
 */
@RestController
@Api(tags = "人员模块")
@RequestMapping("/user/staff")
public class StaffController {

    private final static String CACHE_PREFIX = "captcha::";

    final IStaffService staffService;

    final RedisTemplate redisTemplate;

    public StaffController(@Qualifier("StaffServiceImpl") IStaffService staffService, RedisTemplate redisTemplate) {
        this.staffService = staffService;
        this.redisTemplate = redisTemplate;
    }

    @PostMapping
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("添加人员")
    public RestResponse addStaff(@RequestBody StaffInsertDTO staff) {
        Staff insertStaff = new Staff();
        staff.setUserPassword(DigesterUtil.digestHaxWithSalt(staff.getUserPassword(), staff.getUserName()));
        BeanUtils.copyProperties(staff, insertStaff);
        String userName = staff.getUserName();
        Staff existStaff = staffService.selectStaffByUsername(userName);
        if (existStaff != null) {
            return RestResponse.fail(SystemCode.ParameterValidError.getCode(), "用户名已经存在");
        }
        boolean result = staffService.addStaff(insertStaff);
        if (result) {
            return RestResponse.ok();
        }
        else {
            return RestResponse.fail(SystemCode.InnerError.getCode(), SystemCode.InnerError.getMessage());
        }
    }

    @GetMapping("info")
    @SaCheckLogin
    @ApiOperation("获取当前登录账号的信息")
    public RestResponse<UserInfoDTO> getLoginStaffInfo(@TokenToStaff Staff staff) {
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        BeanUtils.copyProperties(staff, userInfoDTO);
        return RestResponse.ok(userInfoDTO);
    }

    @GetMapping
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("获取人员列表")
    public RestResponse<List<StaffSelectDTO>> selectStaff() {
        List<StaffSelectDTO> staffSelectDTOS = staffService.selectStaffList();
        return RestResponse.ok(staffSelectDTOS);
    }

    @GetMapping("{name}/{current}/{size}")
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("根据人员姓名获取人员信息分页查询")
    public RestResponse<StaffPageDTO> selectStaffByName(@PathVariable String name,
                                                        @PathVariable Integer current,
                                                        @PathVariable Integer size,
                                                        @ApiIgnore @TokenToStaff Staff loginStaff) {
        QueryWrapper<Staff> staffQueryWrapper = new QueryWrapper<>();
        staffQueryWrapper.lambda().like(Staff::getName, name).lt(Staff::getRole, loginStaff.getRole().getId());
        Page<Staff> page = new Page<>(current, size);
        Page<Staff> staffPage = staffService.page(page, staffQueryWrapper);
        boolean hasNext = staffPage.hasNext();
        boolean hasPre = staffPage.hasPrevious();
        List<StaffSelectDTO> staffList = staffPage.getRecords().stream()
                .map(item -> {
                    StaffSelectDTO staffSelectDTO = new StaffSelectDTO();
                    BeanUtils.copyProperties(item, staffSelectDTO);
                    return staffSelectDTO;
                }).collect(Collectors.toList());
        StaffPageDTO staffPageDTO = new StaffPageDTO(staffList, hasNext, hasPre);
        return RestResponse.ok(staffPageDTO);
    }

    @GetMapping("{current}/{size}")
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("分页获取人员列表")
    public RestResponse<StaffPageDTO> selectStaffPages(@PathVariable Integer current,
                                                       @PathVariable Integer size,
                                                       @ApiIgnore @TokenToStaff Staff loginStaff) {
        Page<Staff> page = new Page<>();
        page.setCurrent(current);
        page.setSize(size);
        QueryWrapper<Staff> staffQueryWrapper = new QueryWrapper<>();
        staffQueryWrapper.lambda().lt(Staff::getRole, loginStaff.getRole().getId());
        Page<Staff> resultPage = staffService.page(page, staffQueryWrapper);
        List<StaffSelectDTO> staffList = resultPage.getRecords().stream()
                .map(item -> {
                    StaffSelectDTO staffSelectDTO = new StaffSelectDTO();
                    BeanUtils.copyProperties(item, staffSelectDTO);
                    return staffSelectDTO;
                }).collect(Collectors.toList());
        StaffPageDTO staffPageDTO = new StaffPageDTO(staffList, resultPage.hasNext(), resultPage.hasPrevious());
        return RestResponse.ok(staffPageDTO);
    }

    @PostMapping("login")
    @ApiOperation("用户登录")
    public RestResponse<Map<String, String>> login(@RequestBody UserLoginDTO user) {
        String verify = (String) redisTemplate.opsForValue().get(CACHE_PREFIX + user.getKey());
        if (verify == null || !verify.equals(user.getVerify().toLowerCase())) {
            return RestResponse.fail(SystemCode.ParameterValidError.getCode(), "验证码错误");
        }
        redisTemplate.delete(CACHE_PREFIX + user.getKey());
        Staff staff = staffService.selectStaffByUsername(user.getUsername());
        if (staff == null) {
            return RestResponse.fail(SystemCode.AuthError.getCode(), SystemCode.AuthError.getMessage());
        }
        if (staff.getIsDisable() == 1) {
            return RestResponse.fail(SystemCode.AccessDenied.getCode(), "用户账号已经被禁用，请联系管理员");
        }
        if (staff.getUserPassword().equals(DigesterUtil.digestHaxWithSalt(user.getPassword(), user.getUsername()))) {
            StpUtil.login(user.getUsername());
            String tokenValue = StpUtil.getTokenValue();
            Map<String, String> map = new HashMap<>();
            map.put("token", tokenValue);
            map.put("name", staff.getName());
            return RestResponse.ok(map);
        } else {
            return RestResponse.fail(SystemCode.AuthError.getCode(), SystemCode.AuthError.getMessage());
        }
    }

    @GetMapping("captcha")
    @ApiOperation("获取验证码")
    public RestResponse<CaptchaDTO> captcha() {
        GifCaptcha lineCaptcha = CaptchaUtil.createGifCaptcha(80, 40);
        String imageBase64 = lineCaptcha.getImageBase64();
        String verCode = lineCaptcha.getCode().toLowerCase(Locale.ROOT);
        String key = IdUtil.simpleUUID();
        redisTemplate.opsForValue().set(CACHE_PREFIX + key, verCode, 3, TimeUnit.MINUTES);
        CaptchaDTO captchaDTO = new CaptchaDTO(key, imageBase64);
        return RestResponse.ok(captchaDTO);
    }

    @GetMapping("getAsyncRoutes")
    @ApiOperation("动态获取操作菜单")
    public RestResponse<String> getAsyncRoutes(@TokenToStaff Staff loginStaff) {
        String studentMenu = "[{\"path\":\"/award\",\"name\":\"award\",\"redirect\":\"/award/list\",\"meta\":{\"icon\":\"el-icon-trophy\",\"title\":\"message.hsaward\",\"showLink\":true,\"savedPosition\":true,\"rank\":1},\"children\":[{\"path\":\"/award/add\",\"name\":\"addAward\",\"meta\":{\"title\":\"message.hsassaward\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/award/list\",\"name\":\"listAward\",\"meta\":{\"title\":\"message.hslistaward\",\"showLink\":true,\"savedPosition\":true}}]},{\"path\":\"/yuque\",\"name\":\"yuque\",\"redirect\":\"/yuque\",\"meta\":{\"icon\":\"el-icon-collection\",\"title\":\"message.hsyuque\",\"showLink\":true,\"savedPosition\":true,\"rank\":10},\"children\":[{\"path\":\"/yuque\",\"name\":\"yuque\",\"meta\":{\"title\":\"message.hsyuque\",\"showLink\":true,\"savedPosition\":true}}]}]";
//        String studentMenu = "[{\"path\":\"/permission\",\"name\":\"permission\",\"redirect\":\"/permission/page\",\"meta\":{\"title\":\"message.permission\",\"icon\":\"el-icon-lollipop\",\"showLink\":true,\"savedPosition\":true,\"rank\":3},\"children\":[{\"path\":\"/permission/page\",\"name\":\"permissionPage\",\"meta\":{\"title\":\"message.permissionPage\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/permission/button\",\"name\":\"permissionButton\",\"meta\":{\"title\":\"message.permissionButton\",\"showLink\":true,\"savedPosition\":true,\"authority\":[\"v-test\"]}}]}]";
//        String teacherMenu = "[{\"path\":\"/system\",\"name\":\"system\",\"redirect\":\"/system/user\",\"meta\":{\"icon\":\"el-icon-setting\",\"title\":\"message.hssysManagement\",\"showLink\":true,\"savedPosition\":true,\"rank\":6},\"children\":[{\"path\":\"/system/user\",\"name\":\"user\",\"meta\":{\"title\":\"message.hsBaseinfo\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/system/dict\",\"name\":\"dict\",\"meta\":{\"title\":\"message.hsDict\",\"showLink\":true,\"savedPosition\":true}}]},{\"path\":\"/permission\",\"name\":\"permission\",\"redirect\":\"/permission/page\",\"meta\":{\"title\":\"message.permission\",\"icon\":\"el-icon-lollipop\",\"showLink\":true,\"savedPosition\":true,\"rank\":3},\"children\":[{\"path\":\"/permission/page\",\"name\":\"permissionPage\",\"meta\":{\"title\":\"message.permissionPage\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/permission/button\",\"name\":\"permissionButton\",\"meta\":{\"title\":\"message.permissionButton\",\"showLink\":true,\"savedPosition\":true,\"authority\":[\"v-admin\"]}}]}]";
        String teacherMenu = "[{\"path\":\"/award\",\"name\":\"award\",\"redirect\":\"/award/list\",\"meta\":{\"icon\":\"el-icon-trophy\",\"title\":\"message.hsaward\",\"showLink\":true,\"savedPosition\":true,\"rank\":1},\"children\":[{\"path\":\"/award/list\",\"name\":\"listAward\",\"meta\":{\"title\":\"message.hslistaward\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/award/teacher\",\"name\":\"/teacherAwardIndex\",\"meta\":{\"title\":\"message.hsteacherawardindex\",\"showLink\":true,\"savedPosition\":true}}]},{\"path\":\"/staff\",\"name\":\"staff\",\"redirect\":\"/staff/listStaff\",\"meta\":{\"icon\":\"el-icon-user\",\"title\":\"message.hsstaff\",\"showLink\":true,\"savedPosition\":false,\"rank\":2},\"children\":[{\"path\":\"/staff/addStaff\",\"name\":\"addStaff\",\"meta\":{\"title\":\"message.hsstaffadd\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/staff/listStaff\",\"name\":\"listStaff\",\"meta\":{\"title\":\"message.hsstafflist\",\"showLink\":true,\"savedPosition\":true}},{\"path\":\"/staff/addStaffList\",\"name\":\"addStaffList\",\"meta\":{\"title\":\"message.hsstaffaddlist\",\"showLink\":true,\"savedPosition\":true}}]},{\"path\":\"/yuque\",\"name\":\"yuque\",\"redirect\":\"/yuque\",\"meta\":{\"icon\":\"el-icon-collection\",\"title\":\"message.hsyuque\",\"showLink\":true,\"savedPosition\":true,\"rank\":10},\"children\":[{\"path\":\"/yuque\",\"name\":\"yuque\",\"meta\":{\"title\":\"message.hsyuque\",\"showLink\":true,\"savedPosition\":true}}]}]";
        if (loginStaff.getRole().getId() > RoleEnum.student.getId()) {
            return RestResponse.ok(teacherMenu);
        } else {
            return RestResponse.ok(studentMenu);
        }
    }

    @PostMapping("addList")
    @ApiOperation("使用excel批量添加人员")
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    public RestResponse<String> addList(MultipartFile file) {
        return staffService.addList(file);
    }

    @PutMapping
    @ApiOperation("修改人员信息")
    public RestResponse<String> updateStaff(@RequestBody StaffUpdateDTO staff, @ApiIgnore @TokenToStaff Staff loginStaff) {
        return staffService.updateStaff(staff, loginStaff);
    }

    @GetMapping("/disable/{id}")
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("禁用人员")
    public RestResponse<String> disableStaff(@PathVariable @ApiParam("需要禁用的账户id") Integer id,
                                             @ApiIgnore @TokenToStaff Staff loginStaff) {
        return staffService.disableStaff(id, loginStaff);
    }

    @GetMapping("enable/{id}")
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("启用人员")
    public RestResponse<String> enableStaff(@PathVariable @ApiParam("需要启用的账户id") Integer id,
                                            @ApiIgnore @TokenToStaff Staff loginStaff) {
        return staffService.enableStaff(id, loginStaff);
    }

    @DeleteMapping("/{id}")
    @SaCheckRole(value = {"teacher", "admin"},mode = SaMode.OR)
    @ApiOperation("删除人员")
    public RestResponse<String> deleteStaff(@PathVariable @ApiParam("需要删除的账户id") Integer id,
                                            @ApiIgnore @TokenToStaff Staff loginStaff) {
        return staffService.deleteStaff(id, loginStaff);
    }

    @PutMapping("/selfModify")
    @SaCheckLogin
    @ApiOperation("修改自己的信息")
    public RestResponse modifySelf(@TokenToStaff Staff loginStaff, @RequestBody UserInfoDTO userInfoDTO) {
        return staffService.modifySelf(loginStaff, userInfoDTO);
    }

    @PutMapping("/modifyPwd")
    @SaCheckLogin
    @ApiOperation("修改密码")
    public RestResponse modifyPwd(@TokenToStaff Staff loginStaff, @RequestBody Map<String, String> map) {
        String pwd = map.get("pwd");
        return staffService.modifyPwd(loginStaff, pwd);
    }

}

